//  -------------------- iSharePoint -------------------- //
// 
//  Company:	IT Complex, LLC
//  Project:	Smart.Common
//  File name:	Cortege.cs
//  Developer:	Solomatov Igor
//  Created:	15.04.2012
// 
//  -------------------- iSharePoint -------------------- //

using System;
using System.Diagnostics;

namespace Smart
{
	/// <summary>
	/// Cortege of values
	/// </summary>
	[Serializable]
	public struct Cortege
	{
		public readonly bool IgnoreCase;
		public object[] Args;

		/// <summary>
		/// Cortege of values
		/// </summary>	
		[DebuggerStepThrough]
		public Cortege(bool ignoreCase, params object[] args)
		{
			Args = args;
			IgnoreCase = ignoreCase;
		}

		/// <summary>
		/// Set or get arg by <paramref name="idx"/>
		/// </summary>
		public object this[int idx]
		{
			get { return Args[idx]; }
			set { Args[idx] = value; }
		}

		// override object.Equals
		public override bool Equals(object obj)
		{
			if (obj == null || GetType() != obj.GetType())
				return false;

			var cortege = (Cortege)obj;

			if (Args == cortege.Args)
				return true;

			if (Args == null || cortege.Args == null)
				return false;

			if (Args.Length != cortege.Args.Length)
				return false;

			if (IgnoreCase)
			{
				for (int i = 0, iCnt = Args == null ? 0 : Args.Length; i < iCnt; i++)
				{
					var argl = Args[i];
					var argr = cortege.Args[i];

					if (argl == null && argr == null)
						continue;

					if (argl == null || argr == null)
						return false;

					var argls = argl as string;
					var argrs = argr as string;

					if (argls != null && argrs != null)
					{
						// strings
						if (!string.Equals(argls, argrs, StringComparison.OrdinalIgnoreCase))
							return false;
					}
					else
					{
						// other types
						if (!Equals(argl, argr))
							return false;
					}
				}
			}
			else
			{
				for (int i = 0, iCnt = Args == null ? 0 : Args.Length; i < iCnt; i++)
				{
					if (!Equals(Args[i], cortege.Args[i]))
						return false;
				}
			}

			return true;
		}

		// override object.GetHashCode
		public override int GetHashCode()
		{
			if (Args == null)
				return 0;

			var hash = 0;

			if (IgnoreCase)
			{
				for (int i = 0, iCnt = Args == null ? 0 : Args.Length; i < iCnt; i++)
				{
					var arg = Args[i];

					if (arg == null)
						continue;

					var args = arg as string;

					if (args != null)
					{
						// string
						hash ^= StringComparer.OrdinalIgnoreCase.GetHashCode(args);
					}
					else
					{
						// other types
						hash ^= arg.GetHashCode();
					}
				}
			}
			else
			{
				for (int i = 0, iCnt = Args == null ? 0 : Args.Length; i < iCnt; i++)
				{
					var arg = Args[i];

					if (arg == null)
						continue;

					hash ^= arg.GetHashCode();
				}
			}

			return hash;
		}
	}

	/// <summary>
	/// Cortege of values
	/// </summary>
	[Serializable]
	public struct Cortege<TArg1, TArg2>
	{
		public readonly bool IgnoreCase;

		public TArg1 Arg1;
		public TArg2 Arg2;

		/// <summary>
		/// Cortege of values
		/// </summary>
		[DebuggerStepThrough]
		public Cortege(TArg1 arg1, TArg2 arg2)
			: this(false, arg1, arg2)
		{
		}

		/// <summary>
		/// Cortege of values
		/// </summary>
		[DebuggerStepThrough]
		public Cortege(bool ignoreCase, TArg1 arg1, TArg2 arg2)
		{
			IgnoreCase = ignoreCase;

			Arg1 = arg1;
			Arg2 = arg2;
		}

		// override object.Equals
		public override bool Equals(object obj)
		{
			if (obj == null || GetType() != obj.GetType())
				return false;

			var cortege = (Cortege<TArg1, TArg2>)obj;

			if (IgnoreCase)
			{
				bool res;

				if (typeof(TArg1) == typeof(string))
					res = string.Equals(Arg1.SToStr(null), cortege.Arg1.SToStr(null), StringComparison.OrdinalIgnoreCase);
				else
					res = Equals(Arg1, cortege.Arg1);

				if (!res)
					return false;

				if (typeof(TArg2) == typeof(string))
					res = string.Equals(Arg2.SToStr(null), cortege.Arg2.SToStr(null), StringComparison.OrdinalIgnoreCase);
				else
					res = Equals(Arg2, cortege.Arg2);

				return res;
			}

			return
				Equals(Arg1, cortege.Arg1) && Equals(Arg2, cortege.Arg2);
		}

		// override object.GetHashCode
		public override int GetHashCode()
		{
			if (IgnoreCase)
			{
				int res;

				if (typeof(TArg1) == typeof(string))
					res = Arg1.SToStr(null).GetHashCodeIgnoreCase();
				else
					res = Arg1.SafeGetHashCode();

				if (typeof(TArg2) == typeof(string))
					res ^= Arg2.SToStr(null).GetHashCodeIgnoreCase();
				else
					res ^= Arg2.SafeGetHashCode();

				return res;
			}

			return Arg1.SafeGetHashCode() ^ Arg2.SafeGetHashCode();
		}
	}

	/// <summary>
	/// Cortege of values
	/// </summary>
	[Serializable]
	public struct Cortege<TArg1, TArg2, TArg3>
	{
		public readonly bool IgnoreCase;

		public TArg1 Arg1;
		public TArg2 Arg2;
		public TArg3 Arg3;

		/// <summary>
		/// Cortege of values
		/// </summary>
		[DebuggerStepThrough]
		public Cortege(TArg1 arg1, TArg2 arg2, TArg3 arg3)
			: this(false, arg1, arg2, arg3)
		{
		}

		/// <summary>
		/// Cortege of values
		/// </summary>
		[DebuggerStepThrough]
		public Cortege(bool ignoreCase, TArg1 arg1, TArg2 arg2, TArg3 arg3)
		{
			IgnoreCase = ignoreCase;

			Arg1 = arg1;
			Arg2 = arg2;
			Arg3 = arg3;
		}

		// override object.Equals
		public override bool Equals(object obj)
		{
			if (obj == null || GetType() != obj.GetType())
				return false;

			var cortege = (Cortege<TArg1, TArg2, TArg3>)obj;

			if (IgnoreCase)
			{
				bool res;

				if (typeof(TArg1) == typeof(string))
					res = string.Equals(Arg1.SToStr(null), cortege.Arg1.SToStr(null), StringComparison.OrdinalIgnoreCase);
				else
					res = Equals(Arg1, cortege.Arg1);

				if (!res)
					return false;

				if (typeof(TArg2) == typeof(string))
					res = string.Equals(Arg2.SToStr(null), cortege.Arg2.SToStr(null), StringComparison.OrdinalIgnoreCase);
				else
					res = Equals(Arg2, cortege.Arg2);

				if (!res)
					return false;

				if (typeof(TArg3) == typeof(string))
					res = string.Equals(Arg3.SToStr(null), cortege.Arg3.SToStr(null), StringComparison.OrdinalIgnoreCase);
				else
					res = Equals(Arg3, cortege.Arg3);

				return res;
			}

			return
				Equals(Arg1, cortege.Arg1) && Equals(Arg2, cortege.Arg2) && Equals(Arg3, cortege.Arg3);
		}

		// override object.GetHashCode
		public override int GetHashCode()
		{
			if (IgnoreCase)
			{
				int res;

				if (typeof(TArg1) == typeof(string))
					res = Arg1.SToStr(null).GetHashCodeIgnoreCase();
				else
					res = Arg1.SafeGetHashCode();

				if (typeof(TArg2) == typeof(string))
					res ^= Arg2.SToStr(null).GetHashCodeIgnoreCase();
				else
					res ^= Arg2.SafeGetHashCode();

				if (typeof(TArg3) == typeof(string))
					res ^= Arg3.SToStr(null).GetHashCodeIgnoreCase();
				else
					res ^= Arg3.SafeGetHashCode();

				return res;
			}

			return Arg1.SafeGetHashCode() ^ Arg2.SafeGetHashCode() ^ Arg3.SafeGetHashCode();
		}
	}

	/// <summary>
	/// Cortege of values
	/// </summary>
	[Serializable]
	public struct Cortege<TArg1, TArg2, TArg3, TArg4>
	{
		public readonly bool IgnoreCase;

		public TArg1 Arg1;
		public TArg2 Arg2;
		public TArg3 Arg3;
		public TArg4 Arg4;

		/// <summary>
		/// Cortege of values
		/// </summary>
		[DebuggerStepThrough]
		public Cortege(TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4)
			: this(false, arg1, arg2, arg3, arg4)
		{
		}

		/// <summary>
		/// Cortege of values
		/// </summary>
		[DebuggerStepThrough]
		public Cortege(bool ignoreCase, TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4)
		{
			IgnoreCase = ignoreCase;

			Arg1 = arg1;
			Arg2 = arg2;
			Arg3 = arg3;
			Arg4 = arg4;
		}

		// override object.Equals
		public override bool Equals(object obj)
		{
			if (obj == null || GetType() != obj.GetType())
				return false;

			var cortege = (Cortege<TArg1, TArg2, TArg3, TArg4>)obj;

			if (IgnoreCase)
			{
				bool res;

				if (typeof(TArg1) == typeof(string))
					res = string.Equals(Arg1.SToStr(null), cortege.Arg1.SToStr(null), StringComparison.OrdinalIgnoreCase);
				else
					res = Equals(Arg1, cortege.Arg1);

				if (!res)
					return false;

				if (typeof(TArg2) == typeof(string))
					res = string.Equals(Arg2.SToStr(null), cortege.Arg2.SToStr(null), StringComparison.OrdinalIgnoreCase);
				else
					res = Equals(Arg2, cortege.Arg2);

				if (!res)
					return false;

				if (typeof(TArg3) == typeof(string))
					res = string.Equals(Arg3.SToStr(null), cortege.Arg3.SToStr(null), StringComparison.OrdinalIgnoreCase);
				else
					res = Equals(Arg3, cortege.Arg3);

				if (!res)
					return false;

				if (typeof(TArg4) == typeof(string))
					res = string.Equals(Arg4.SToStr(null), cortege.Arg4.SToStr(null), StringComparison.OrdinalIgnoreCase);
				else
					res = Equals(Arg4, cortege.Arg4);

				return res;
			}

			return
				Equals(Arg1, cortege.Arg1) && Equals(Arg2, cortege.Arg2) && Equals(Arg3, cortege.Arg3) && Equals(Arg4, cortege.Arg4);
		}

		// override object.GetHashCode
		public override int GetHashCode()
		{
			if (IgnoreCase)
			{
				int res;

				if (typeof(TArg1) == typeof(string))
					res = Arg1.SToStr(null).GetHashCodeIgnoreCase();
				else
					res = Arg1.SafeGetHashCode();

				if (typeof(TArg2) == typeof(string))
					res ^= Arg2.SToStr(null).GetHashCodeIgnoreCase();
				else
					res ^= Arg2.SafeGetHashCode();

				if (typeof(TArg3) == typeof(string))
					res ^= Arg3.SToStr(null).GetHashCodeIgnoreCase();
				else
					res ^= Arg3.SafeGetHashCode();

				if (typeof(TArg4) == typeof(string))
					res ^= Arg4.SToStr(null).GetHashCodeIgnoreCase();
				else
					res ^= Arg4.SafeGetHashCode();

				return res;
			}

			return Arg1.SafeGetHashCode() ^ Arg2.SafeGetHashCode() ^ Arg3.SafeGetHashCode() ^ Arg4.SafeGetHashCode();
		}
	}

	/// <summary>
	/// Cortege of values
	/// </summary>
	[Serializable]
	public struct Cortege<TArg1, TArg2, TArg3, TArg4, TArg5>
	{
		public readonly bool IgnoreCase;

		public TArg1 Arg1;
		public TArg2 Arg2;
		public TArg3 Arg3;
		public TArg4 Arg4;
		public TArg5 Arg5;

		/// <summary>
		/// Cortege of values
		/// </summary>
		[DebuggerStepThrough]
		public Cortege(TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, TArg5 arg5)
			: this(false, arg1, arg2, arg3, arg4, arg5)
		{
		}

		/// <summary>
		/// Cortege of values
		/// </summary>
		[DebuggerStepThrough]
		public Cortege(bool ignoreCase, TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, TArg5 arg5)
		{
			IgnoreCase = ignoreCase;

			Arg1 = arg1;
			Arg2 = arg2;
			Arg3 = arg3;
			Arg4 = arg4;
			Arg5 = arg5;
		}

		// override object.Equals
		public override bool Equals(object obj)
		{
			if (obj == null || GetType() != obj.GetType())
				return false;

			var cortege = (Cortege<TArg1, TArg2, TArg3, TArg4, TArg5>)obj;

			if (IgnoreCase)
			{
				bool res;

				if (typeof(TArg1) == typeof(string))
					res = string.Equals(Arg1.SToStr(null), cortege.Arg1.SToStr(null), StringComparison.OrdinalIgnoreCase);
				else
					res = Equals(Arg1, cortege.Arg1);

				if (!res)
					return false;

				if (typeof(TArg2) == typeof(string))
					res = string.Equals(Arg2.SToStr(null), cortege.Arg2.SToStr(null), StringComparison.OrdinalIgnoreCase);
				else
					res = Equals(Arg2, cortege.Arg2);

				if (!res)
					return false;

				if (typeof(TArg3) == typeof(string))
					res = string.Equals(Arg3.SToStr(null), cortege.Arg3.SToStr(null), StringComparison.OrdinalIgnoreCase);
				else
					res = Equals(Arg3, cortege.Arg3);

				if (!res)
					return false;

				if (typeof(TArg4) == typeof(string))
					res = string.Equals(Arg4.SToStr(null), cortege.Arg4.SToStr(null), StringComparison.OrdinalIgnoreCase);
				else
					res = Equals(Arg4, cortege.Arg4);

				if (!res)
					return false;

				if (typeof(TArg5) == typeof(string))
					res = string.Equals(Arg5.SToStr(null), cortege.Arg5.SToStr(null), StringComparison.OrdinalIgnoreCase);
				else
					res = Equals(Arg5, cortege.Arg5);

				return res;
			}

			return
				Equals(Arg1, cortege.Arg1) && Equals(Arg2, cortege.Arg2) && Equals(Arg3, cortege.Arg3) && Equals(Arg4, cortege.Arg4) && Equals(Arg5, cortege.Arg5);
		}

		// override object.GetHashCode
		public override int GetHashCode()
		{
			if (IgnoreCase)
			{
				int res;

				if (typeof(TArg1) == typeof(string))
					res = Arg1.SToStr(null).GetHashCodeIgnoreCase();
				else
					res = Arg1.SafeGetHashCode();

				if (typeof(TArg2) == typeof(string))
					res ^= Arg2.SToStr(null).GetHashCodeIgnoreCase();
				else
					res ^= Arg2.SafeGetHashCode();

				if (typeof(TArg3) == typeof(string))
					res ^= Arg3.SToStr(null).GetHashCodeIgnoreCase();
				else
					res ^= Arg3.SafeGetHashCode();

				if (typeof(TArg4) == typeof(string))
					res ^= Arg4.SToStr(null).GetHashCodeIgnoreCase();
				else
					res ^= Arg4.SafeGetHashCode();

				if (typeof(TArg5) == typeof(string))
					res ^= Arg5.SToStr(null).GetHashCodeIgnoreCase();
				else
					res ^= Arg5.SafeGetHashCode();

				return res;
			}

			return Arg1.SafeGetHashCode() ^ Arg2.SafeGetHashCode() ^ Arg3.SafeGetHashCode() ^ Arg4.SafeGetHashCode() ^ Arg5.SafeGetHashCode();
		}
	}
}